
#include <string.h>
#include <assert.h>

#include "ClassFileConstant.h"
#include "SimpleIo.h"
#include "ConstantPool.h"


ClassFileConstant::ClassFileConstant(u1 tag,const char * descr) 
{ 
  this->tag=tag; this->descr=descr; 
};

ClassFileConstantString::ClassFileConstantString(FILE *f) 
    : ClassFileConstant(CONSTANT_String,"Constant String")
{
    string_index=readUint16(f);
}

void ClassFileConstantString::save(FILE *f)
{
  writeUint8(f,tag);
  writeUint16(f,string_index);
}

ClassFileConstantClass::ClassFileConstantClass(u2 name_index)
    : ClassFileConstant(CONSTANT_Class,"Constant Class")
{
  this->name_index=name_index;
}

void ClassFileConstantClass::save(FILE *f)
{
  writeUint8(f,tag);
  writeUint16(f,name_index);
}

ClassFileConstantUnicode::ClassFileConstantUnicode(u2 length,u2 * bytes)
    : ClassFileConstant(CONSTANT_Unicode,"Constant Unicode")
{
  this->length=length;
  this->bytes=new u2[length];
  memcpy(this->bytes,bytes,length*2);
}

void ClassFileConstantUnicode::save(FILE *f)
{
  writeUint8(f,tag);
  writeUint16(f,length);
  for(u2 i=0;i<length;i++) 
    writeUint16(f,length);
}

ClassFileConstantMethodRef::ClassFileConstantMethodRef(u2 class_index,u2 name_and_type_index)
    : ClassFileConstant(CONSTANT_Methodref,"Constant Method Ref")
{
  this->class_index=class_index;
  this->name_and_type_index=name_and_type_index;
}

void ClassFileConstantMethodRef::save(FILE *f)
{
  writeUint8(f,tag);
  writeUint16(f,class_index);
  writeUint16(f,name_and_type_index);
}


ClassFileConstantNameAndType::ClassFileConstantNameAndType(ConstantPool * cp, 
    const char * name, const char * signature)
    : ClassFileConstant(CONSTANT_NameAndType,"Constant Name And Type")
{
  name_index=cp->addUtf8(name);
  signature_index=cp->addUtf8(signature);
}

ClassFileConstantNameAndType::ClassFileConstantNameAndType(FILE *f) 
    : ClassFileConstant(CONSTANT_NameAndType,"Constant Name And Type")
{
  name_index=readUint16(f);
  signature_index=readUint16(f);
}

void ClassFileConstantNameAndType::save(FILE *f) 
{
  writeUint8(f,tag);
  writeUint16(f,name_index);
  writeUint16(f,signature_index);
}


ClassFileConstantFieldRef::ClassFileConstantFieldRef(
    u2 class_index,
    u2 name_and_type_index)
    : ClassFileConstant(CONSTANT_Fieldref,"Constant Field Reference")
{
  this->class_index=class_index;
  this->name_and_type_index=name_and_type_index;
}

ClassFileConstantFieldRef::ClassFileConstantFieldRef(FILE * f)
    : ClassFileConstant(CONSTANT_Fieldref,"Constant Field Reference")
{
  class_index=readUint16(f);
  name_and_type_index=readUint16(f);
}

void ClassFileConstantFieldRef::save(FILE * f)
{
  writeUint8(f,tag);
  writeUint16(f,class_index);
  writeUint16(f,name_and_type_index);
}

void ClassFileConstantDouble::dump(ConstantPool * cp, bool complete)
{
  double * d=(double*)&low_bytes;
  if(complete)
    printf("Double           ");
  printf("%lf",*d);
}

void ClassFileConstantDouble::save(FILE * f)
{
  writeUint8(f,tag);
  writeUint32(f,high_bytes);
  writeUint32(f,low_bytes);
}

ClassFileConstantDouble::ClassFileConstantDouble(double d)
    : ClassFileConstant(CONSTANT_Double,"Constant Double")
{
 *(double*)&low_bytes=d;
#if 0
 low_bytes=0;
 high_bytes=1;
#endif
}

ClassFileConstantDouble::ClassFileConstantDouble(FILE * f)
    : ClassFileConstant(CONSTANT_Double,"Constant Double")
{
  high_bytes=readUint32(f);
  low_bytes=readUint32(f);
}

ClassFileConstantInteger::ClassFileConstantInteger(FILE * f)
    : ClassFileConstant(CONSTANT_Integer,"Constant Integer")
{
  bytes=readUint32(f);
}

void ClassFileConstantInteger::save(FILE * f)
{
  writeUint8(f,tag);
  writeUint32(f,bytes);
}

ClassFileConstantUtf8::ClassFileConstantUtf8(const char * cstring) 
    : ClassFileConstant(CONSTANT_Utf8,"Constant Utf8")
{
  length=strlen(cstring);
  string=new char[length+1];
  strcpy(string,cstring);
}

ClassFileConstantUtf8::ClassFileConstantUtf8(FILE *f) 
    : ClassFileConstant(CONSTANT_Utf8,"Constant Utf8")
{
  length=readUint16(f);
  u1 ch;
  u2 i;
  string=new char[length+1];
  for(i=0;i<length;i++) {
    ch=readUint8(f);
    assert(ch<=0x7F);
    string[i]=ch;
  }
  string[i]=0;
}

void ClassFileConstantUtf8::save(FILE *f) 
{
  writeUint8(f,tag);
  writeUint16(f,length);
  for(u2 i=0;i<length;i++)
    writeUint8(f,string[i]);
}

void ClassFileConstantInteger::dump(ConstantPool * cp, bool complete)
{
  if(complete)
    printf("Integer          ");
  printf("%d",bytes);
}

void ClassFileConstantString::dump(ConstantPool * cp, bool complete)
{
  ClassFileConstant * pointed;
  if(complete)
    printf("String           '");
  else 
    printf("'");
  pointed=cp->getAt(string_index);
  pointed->dump(cp);
  printf("'");
}

ClassFileConstantClass::ClassFileConstantClass(ConstantPool * cp, const char * name)
    : ClassFileConstant(CONSTANT_Class,"Constant Class")
{
  name_index=cp->addUtf8(name);
}

ClassFileConstantString::ClassFileConstantString(u2 utf8_index)
    : ClassFileConstant(CONSTANT_String,"Constant String")
{
  string_index=utf8_index;
}

void ClassFileConstantClass::dump(ConstantPool * cp, bool complete)
{
  ClassFileConstant * pointed;
  if(complete)
    printf("Class            <%d>",name_index);
  pointed=cp->getAt(name_index);
  pointed->dump(cp);
}

void ClassFileConstantUnicode::dump(ConstantPool * cp, bool complete)
{
  printf("Unicode: ");
}

void ClassFileConstantMethodRef::dump(ConstantPool * cp, bool complete)
{
  ClassFileConstant * p1;
  ClassFileConstant * p2;

  p1=cp->getAt(class_index);
  p2=cp->getAt(name_and_type_index);
  if(complete)
    printf("MethodRef        '");
  else 
    printf("'");
  p1->dump(cp);
  printf("' '");
  p2->dump(cp);
  printf("'");
}

void ClassFileConstantNameAndType::dump(ConstantPool * cp, bool complete)
{
  ClassFileConstant * p1;
  ClassFileConstant * p2;

  p1=cp->getAt(name_index);
  p2=cp->getAt(signature_index);
  if(complete)
    printf("NameAndType      <%d>",name_index);
  p1->dump(cp);
  printf(" <%d>",signature_index);
  p2->dump(cp);
}

void ClassFileConstantFieldRef::dump(ConstantPool * cp, bool complete)
{
  ClassFileConstant * p1;
  ClassFileConstant * p2;

  p1=cp->getAt(class_index);
  p2=cp->getAt(name_and_type_index);
  if(complete)
    printf("ConstantFieldRef '");
  else
    printf("'");
  p1->dump(cp);
  printf("' '");
  p2->dump(cp);
  printf("'");
}

void ClassFileConstantUtf8::dump(ConstantPool * cp,bool complete)
{
  if(complete) 
    printf("Utf8             ");
  printf("%s",string);
}
